#include "tempprocess.h"

double crossProduct(const QPoint &a, const QPoint &b, const QPoint &c) {
    return (b.x() - a.x()) * (c.y() - a.y()) - (b.y() - a.y()) * (c.x() - a.x());
}

double eurDistance(const QPoint &a, const QPoint &b)
{
    if(a.x() == b.x() && a.y() == b.y())
    {
        return 0;
    }
    else
    {
        return sqrt(pow((b.x()-a.x()),2) + pow((b.y() - a.y()),2));
    }
}

TempProcess::TempProcess()
{

}
TempProcess::TempProcess(QString fileName)
{
    tmp = loadTempature(fileName,imgH,imgW,tMax,tMin);
    //*tmpMap = setTempMap(fileName);
}
void TempProcess::setTemp(QString fileName)
{
    tmp = loadTempature(fileName,imgH,imgW,tMax,tMin);
    //*tmpMap = setTempMap(fileName);
}

cv::Mat TempProcess::getColorRuler()
{
    cv::Mat RGBcolorMap(imgH, imgW, CV_8UC3);
    //qDebug() << imgH << "," << imgW <<","<< imgH*imgW << "," << tmp->size();
    if(imgH == 0 || imgW == 0)
        return RGBcolorMap;
    double lag = 0.0; //滞后
    double fillR = 0;
    double fillG = 0;
    double fillB = 0;

    int gap = std::abs(tMax - tMin);
    for (auto k = tmp->begin(); k != tmp->end(); k++)
    {
        Point *t = (*k).second;
        lag = (t)->temp - tMin;
        //温度范围
        double tempature = std::min(std::max((t)->temp,-100.0), 100.0);
        double part = abs(lag / (tMax - tMin));
        //颜色映射
        if (part <= 0.1)
        {//黑->蓝
            fillR = 0.0;
            fillG = 0.0;
            fillB = (part * 255.0) / 0.1;
        }
        else if(part >= 0.1 && part < 0.3)
        {//蓝->紫
            fillR = ((part-0.1) * 255.0) / 0.2;
            fillG = 0.0;
            fillB = 255.0;
        }
        else if (part >= 0.3 && part < 0.6)
        {//紫->红
            fillR = 255.0;
            fillG = 0.0;
            fillB = 255 - (((part - 0.3) * 255.0) / 0.3);
        }
        else if (part >= 0.6 && part < 0.95)
        {//红->黄
            fillR = 255;
            fillG = ((part - 0.6) * 255.0) / 0.35;
            fillB = 0;
        }
        else if (part >= 0.95 && part <= 1)
        {//黄->白
            fillR = 255;
            fillG = 255;
            fillB = ((part - 0.95) * 255.0) / 0.05;
        }
        else
        {
            fillR = 0;
            fillG = 0;
            fillB = 0;
        }

        RGBcolorMap.at<cv::Vec3b>((t)->y, (t)->x)[0] = fillB;
        RGBcolorMap.at<cv::Vec3b>((t)->y, (t)->x)[1] = fillG;
        RGBcolorMap.at<cv::Vec3b>((t)->y, (t)->x)[2] = fillR;
    }

    return RGBcolorMap;
}


std::vector<QPoint *> TempProcess::getEnvelope(std::map<QPoint*,QString> pts)
{
    std::map<QPoint*,QString> pt = pts;
    std::vector<cv::Point> pt1;
    std::vector<cv::Point> pt2;
    std::vector<QPoint *> pt3;
    for(auto j : pt)
    {
        pt1.push_back(cv::Point(j.first->x(),j.first->y()));
    }
    //在pt1中寻找凸包
    cv::convexHull(pt1,pt2);

    for(auto m : pt2)
    {
        pt3.push_back(new QPoint(m.x,m.y));
    }
    //QPoint Origin(0,0);
    /*
    int centerX = 0;
    int centerY = 0;
    for (auto p = pt.begin(); p != pt.end(); p++)
    {
        centerX += (*p)->x();
        centerY += (*p)->y();
    }
    centerX = centerX / pt.size();
    centerY = centerY / pt.size();

    QPoint center(centerX,centerY);


    //时钟排序
    std::sort(pt.begin(), pt.end(), [centerX, centerY](const QPoint* p1, const QPoint* p2) {
        //int flag = 1;
        //return atan2(flag * (p1->y() - centerY) , (p1->x() - centerX)) < atan2(flag * (p2->y() - centerY) , (p2->x() - centerX));
        double angle1 = atan2(double(p1->y() - centerY), double(p1->x() - centerX));
        //if (angle1 < 0) angle1 += 2 * M_PI; // 将负角度转换为[0, 2π]

        double angle2 = atan2(double(p2->y() - centerY), double(p2->x() - centerX));
        //if (angle2 < 0) angle2 += 2 * M_PI; // 将负角度转换为[0, 2π]

        angle1 = std::fmod(angle1 + 2 * M_PI, 2 * M_PI);
        angle2 = std::fmod(angle2 + 2 * M_PI, 2 * M_PI);

        return angle1 < angle2;
    });
    return pt;
    */
    return pt3;
}

std::map<QString,Point*>* TempProcess::loadTempature(QString tempFile,int& imgH,int& imgW,double &tMax,double &tMin)
{
    std::map<QString,Point*> *res = new std::map<QString,Point*>();
    //QString->std::string
    QByteArray byteArr = tempFile.toLocal8Bit();
    std::string tmpFile = std::string(byteArr);
    std::ifstream readStream(tmpFile, std::ios::in);
    std::string splitchr = " ";
    int cspos = 0;
    int cepos = 0;
    int endpos = 0;
    int w = 0;
    int h = 0;
    double tmin = 99999.0;
    double tmax = -99999.0;
    if (readStream) //打开成功
    {
       std::string line;
       while (getline(readStream, line))
       {
          endpos = line.rfind(splitchr);
          if (line.size() != 0)
          {
             while ((cepos = line.find(splitchr, cspos)) != std::string::npos)
             {
                 if (cepos > endpos)
                     break;
                 Point *pt = new Point();
                 std::string str = line.substr(cspos,cepos-cspos);
                 //std::cout << str << " ";
                 cspos = cepos + splitchr.length();
                 pt->x = w;
                 pt->y = h;
                 pt->temp = stod(str); //double->string
                 //res.push_back(pt);
                 QString ptStr = QString::number(w) + "," + QString::number(h);
                 res->insert(std::make_pair(ptStr,pt));
                 if (pt->temp > tmax)
                 {
                    tmax = pt->temp;
                 }
                 if (pt->temp < tmin)
                 {
                    tmin = pt->temp;
                 }
                 ++w;

             }
          }
          imgW = w;
          w = 0;
          cspos = 0;
          cepos = 0;
          ++h;
       }
       imgH = h;
       readStream.close();
    }
        tMax = tmax;
        tMin = tmin;
        return res;
}

std::map<std::string, double> TempProcess::setTempMap(QString tempFile)
{
    std::map<std::string, double> tmpMap;
    //QString->std::string
    QByteArray byteArr = tempFile.toLocal8Bit();
    std::string tmpFile = std::string(byteArr);
    std::ifstream readStream(tmpFile, std::ios::in);
    std::string splitchr = " ";
    int cspos = 0;
    int cepos = 0;
    int endpos = 0;
    int w = 0;
    int h = 0;

    if (readStream) //打开成功
    {
        std::string line;
        while (getline(readStream, line))
        {
            endpos = line.rfind(splitchr);
            if (line.size() != 0)
            {
                while ((cepos = line.find(splitchr, cspos)) != std::string::npos)
                {
                    if (cepos > endpos)
                        break;
                    std::string str = line.substr(cspos, cepos - cspos);
                    cspos = cepos + splitchr.length();
                    std::string pos = std::to_string(w) + "," + std::to_string(h);
                    tmpMap.insert(std::make_pair(pos, stod(str)));

                    ++w;
                }
            }
            w = 0;
            cspos = 0;
            cepos = 0;
            //std::cout << std::endl;
            ++h;
        }
        readStream.close();
    }
    return tmpMap;
}

void TempProcess::setTempature(std::map<QString,Point*> *t)
{
        double maxT = -99999.0;
        double minT  = 99999.0;
        int currX = 0;
        int currY = 0;
        *tmp = *t;
        for(auto i = tmp->begin();i!=tmp->end();i++)
        {
            int x = i->second->x;
            int y = i->second->y;
            double t1 = i->second->temp;
            if( t1 > maxT)
            {
                maxT =  t1;
            }
            else if (t1 < minT)
            {
                minT = t1;
            }
            if(x > currX) currX = x;
            if(y > currY) currY = y;
        }
        tMax = maxT;
        tMin = minT;
        //imgW = currX;
        //imgH = currY;

}

cv::Mat TempProcess::showImage(QString fileName)
{
    setTemp(fileName);
    cv::Mat img = getColorRuler();
    cv::Mat finalImg = picUnDistort(img);
    //return img;
    return finalImg;
}

cv::Mat TempProcess::getScaleImage(cv::Mat &img, std::vector<cv::Point> region, std::map<std::string, double>& tmp, std::map<std::string, double> &regionTmp)
{
    cv::Mat output = cv::Mat::zeros(img.size(), CV_8UC3);
    cv::Mat dst = cv::Mat::zeros(img.size(), CV_8UC3);
    cv::Mat roi = cv::Mat::zeros(img.size(), CV_8UC3);
    std::vector<std::vector<cv::Point>> regions;
    cv::Rect regionRect = cv::boundingRect(region);
    //放大选区
    double scaleFactor = 2.0;

    double scaleFactorX = img.size().width / regionRect.width;
    double scaleFactorY = img.size().height / regionRect.height;

    double minX = 99999.0;
    double minY = 99999.0;
    double maxX = -99999.0;
    double maxY = -99999.0;

    //放大区域

     std::vector<cv::Point> enlargedContour;
     std::vector<std::vector<cv::Point>> enlargedContours;
     for (const auto& point : region) {
         cv::Point2f scaledPoint(point.x * scaleFactorX, point.y * scaleFactorY);
         enlargedContour.push_back(scaledPoint);
     }

    enlargedContours.push_back(enlargedContour);
    cv::Mat enlargedDst = cv::Mat::zeros(img.size().height * scaleFactorY,img.size().width * scaleFactorX, CV_8UC3);
    cv::drawContours(enlargedDst, enlargedContours, 0, cv::Scalar(0, 255, 0), -1);
    //填充颜色
    for (int y = 0; y < enlargedDst.rows; ++y)
    {
        for (int x = 0; x < enlargedDst.cols; ++x)
        {
            if (enlargedDst.at<cv::Vec3b>(y, x) != cv::Vec3b(0, 0, 0))
            {
                int srcX = static_cast<int>(x / scaleFactorX);
                int srcY = static_cast<int>(y / scaleFactorY);
                if (srcX >= 0 && srcX < img.cols && srcY >= 0 && srcY < img.rows) {
                    enlargedDst.at<cv::Vec3b>(y, x) = img.at<cv::Vec3b>(srcY, srcX);
                }
            }
        }
    }

    // 计算放大后轮廓的边界框
    cv::Rect rect = cv::boundingRect(enlargedContours.at(0));

    //std::cout << rect.x << "," << rect.y << std::endl;

    // 将放大后的轮廓移动到图像中心
    cv::Mat result = cv::Mat::zeros(enlargedDst.size(), CV_8UC3);
    cv::Rect copyRect(rect.x,
        rect.y,
        rect.width,
        rect.height);
    enlargedDst(copyRect).copyTo(result);

    //填充区域温度
    for (int posy = 0; posy < result.rows; posy++)
    {
        for (int posx = 0; posx < result.cols; posx++)
        {
            if (result.at<cv::Vec3b>(posy, posx) != cv::Vec3b(0, 0, 0))
            {
                std::string pos = std::to_string(posx) + "," + std::to_string(posy);
                std::string pos1 = std::to_string(posx + rect.x) + "," + std::to_string(posy + rect.y);
                regionTmp.insert(std::make_pair(pos, tmp[pos1]));
            }
        }
    }
    return(result);
}
//去畸变
cv::Mat TempProcess::picUnDistort(cv::Mat &img)
{
    cv::Mat UndistortImg;
    cv::Mat camaraMatrix,distortFactor;
    cv::Rect goodRegion;

    //设置像头内参矩阵
    //camaraMatrix = (cv::Mat_<double>(3,3) << 1000, 0, img.cols / 2, 0, 1000, img.rows / 2, 0, 0, 1);
    camaraMatrix = (cv::Mat_<double>(3,3) << 1000, 0, img.cols / 2, 0, 1000, img.rows / 2, 0, 0, 1);

    //设置畸变因子
    distortFactor = (cv::Mat_<double>(1,4) << -1.3,0,0,0);
    //获取畸变矫正矩阵
    //cv::Mat distortCorrect = cv::getOptimalNewCameraMatrix(camaraMatrix,distortFactor,img.size(),1,img.size(),&goodRegion);
    //cv::undistort(img,UndistortImg,camaraMatrix,distortFactor,distortCorrect);
    //UndistortImg = UndistortImg(goodRegion);
    cv::Mat mapx, mapy;
    cv::initUndistortRectifyMap(camaraMatrix,distortFactor,cv::Mat(),camaraMatrix,img.size(),CV_32FC1,mapx,mapy);
    cv::remap(img,UndistortImg,mapx,mapy, cv::INTER_LINEAR);

    //反向填充温度值
    std::map<QString,Point*> *newmap = new std::map<QString,Point*>();
    std::map<QString,Point*> *oldmap = tmp;

    for(int i=0; i < UndistortImg.rows; i++)
    {
        for(int j =0; j < UndistortImg.cols; j++)
        {
            int origX = round(mapx.at<float>(i,j));
            int origY = round(mapy.at<float>(i,j));

            QString ptStr = QString::number(j) + "," + QString::number(i);
            QString findPtStr = QString::number(origX) + "," + QString::number(origY);

            if(tmp->find(findPtStr) != tmp->end())
            {
                Point *pt = new Point();
                pt->x = j;
                pt->y = i;
                pt->temp = tmp->find(findPtStr)->second->temp;
                newmap->insert(std::make_pair(ptStr,pt));
            }
            else
            {
                //Point pt(origX,origY,0);
                //newmap->insert(std::make_pair(ptStr,&pt));
            }

        }
    }
    tmp = newmap;
    delete oldmap;
    return UndistortImg;
}

std::map<QString,Point*> TempProcess::getTempature()
{
    return *tmp;
}
QSize TempProcess::getSize()
{
    return QSize(imgH,imgW);
}
std::pair<double,double> TempProcess::getTmpDiff()
{
    return std::make_pair(tMax,tMin);
}
